package com.wss.lsl.lucene.demo.searcher;

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

public class SearcherUtil {

	// public static final Analyzer ANALYZER = new IKAnalyzer();
	public static final Analyzer ANALYZER = new StandardAnalyzer(
			Version.LUCENE_35);

	private String[] ids = { "1", "2", "3", "4", "5", "6" };
	private String[] emails = { "aa@qq.com", "bb@sina.com", "cc@yahoo.com",
			"dd@chian-rewards.com", "ee@jxt.com", "ff@iaspec.com" };
	private String[] contents = {
			"If you're include completely new to the Apache HTTP Server, or even to running a website at all",
			"you might not you know where to start, or what questions to ask.",
			"This document walks you through the basics.",
			"Addresses on the Web are expressed with URLs - Uniform Resource Locators - which specify a protocol (e.g. http)",
			" a servername (e.g. www.apache.org), a URL-path (e.g. /docs/current/getting-started.html), and possibly a query string (e.g. ?arg=value) used to pass additional arguments to the server. ",
			"Details of the transaction, and any error conditions, are written to log files. This is discussed in greater detail below in the Logs Files and Troubleshooting section." };
	private int[] attachs = { 1, 10, 34, 5, 24, 17 };
	private String[] senders = { "weishengshui", "loushulan", "wss", "lsl",
			"zhangsan", "lisi" };

	private Directory directory;
	private IndexReader reader;

	public SearcherUtil() throws IOException {
		directory = new RAMDirectory();
		index();
	}

	public IndexSearcher getSearcher() throws CorruptIndexException,
			IOException {
		if (reader == null) {
			reader = IndexReader.open(directory);
		} else {
			IndexReader tr = IndexReader.openIfChanged(reader);
			if (tr != null) {
				reader.close();
				reader = tr;
			}
		}
		return new IndexSearcher(reader);
	}

	/**
	 * 精确查询
	 * 
	 * @param field
	 * @param value
	 * @param num
	 */
	public void searchByTerm(String field, String value, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			Query query = new TermQuery(new Term(field, value));
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 字符串范围查询范围查询
	 * 
	 * @param field
	 * @param start
	 * @param end
	 * @param includeLower
	 * @param includeUpper
	 * @param num
	 */
	public void searchByRangeTerm(String field, String start, String end,
			boolean includeLower, boolean includeUpper, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			Query query = new TermRangeQuery(field, start, end, includeLower,
					includeUpper);
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 数字范围查询
	 * 
	 * @param field
	 * @param start
	 * @param end
	 * @param minInclusive
	 * @param maxInclusive
	 * @param num
	 */
	public void searchByNumericTerm(String field, Integer start, Integer end,
			boolean minInclusive, boolean maxInclusive, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			Query query = NumericRangeQuery.newIntRange(field, start, end,
					minInclusive, maxInclusive);
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 前缀查询
	 * 
	 * @param field
	 * @param value
	 * @param num
	 */
	public void searchByPrefixQuery(String field, String value, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			Query query = new PrefixQuery(new Term(field, value));
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 通配符查詢
	 * 
	 * @param field
	 * @param value
	 * @param num
	 */
	public void searchByWildcardQuery(String field, String value, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			Query query = new WildcardQuery(new Term(field, value));
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 逻辑查询
	 * 
	 * @param term1
	 * @param term2
	 * @param num
	 */
	public void searchByBooleanQuery(Term term1, Term term2, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			BooleanQuery query = new BooleanQuery();
			query.add(new TermQuery(term1), BooleanClause.Occur.MUST);
			query.add(new TermQuery(term2), BooleanClause.Occur.MUST);
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 短语查询
	 * 
	 * @param term1
	 * @param term2
	 * @param num
	 */
	public void searchByPhraseQuery(Term term1, Term term2, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			PhraseQuery query = new PhraseQuery();
			query.setSlop(1);
			query.add(term1);
			query.add(term2);
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 模糊查询 
	 * 
	 * @param field
	 * @param value
	 * @param num
	 */
	public void searchByFuzzyQuery(String field, String value, int num) {
		IndexSearcher searcher = null;
		try {
			searcher = getSearcher();
			FuzzyQuery query = new FuzzyQuery(new Term(field, value));
			TopDocs topDocs = searcher.search(query, num);
			System.out.println("Found " + topDocs.totalHits + " hits.");
			for (ScoreDoc hit : topDocs.scoreDocs) {
				Document doc = searcher.doc(hit.doc);
				StringBuilder sb = new StringBuilder();
				for (Fieldable fieldable : doc.getFields()) {
					sb.append(fieldable.name());
					sb.append(": ");
					sb.append(fieldable.stringValue());
					sb.append("\t");
				}
				System.out.println(sb.toString());
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (searcher != null) {
					searcher.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 当writer是单列时，每次添加完索引后，writer不会关闭，使用writer.commit();。关闭实际还有一个提交的操作，
	 * 不然添加的document并不能添加进索引，查询不到数据
	 * 
	 * @throws IOException
	 */
	public void index() throws IOException {
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,
				ANALYZER);
		IndexWriter writer = new IndexWriter(directory, config);
		for (int i = 0, lengt = ids.length; i < lengt; i++) {
			Document document = new Document();
			document.add(new Field("id", ids[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED_NO_NORMS));// 存储 不分词
			document.add(new Field("email", emails[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			document.add(new NumericField("attach", Field.Store.YES, true)
					.setIntValue(attachs[i]));
			document.add(new Field("sender", senders[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			document.add(new Field("content", contents[i], Field.Store.NO,
					Field.Index.ANALYZED)); // 存储 分词

			writer.addDocument(document);
		}
		writer.close();
	}

	public void closeIndex() throws IOException {
		directory.close();
	}
}
